from fastapi import APIRouter, HTTPException, Query, Body, Depends
from pydantic import BaseModel
from typing import List, Dict, Any, Optional
import logging
import json
import os
from datetime import datetime
import database
import auth
from auth import get_current_user
import importlib
from openai import OpenAI
import asyncio
import re
import httpx

# 兼容性说明：
# 此模块已针对Python 3.8及以上版本进行了优化
# 如果使用Python 3.9+，可将本文件中的loop.run_in_executor替换为更简洁的asyncio.to_thread

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

# DeepSeek API配置
DEEPSEEK_API_KEY = os.environ.get("DEEPSEEK_API_KEY", "sk-175ecab4b7a3477b909aff5725e5a6f3")  # 实际应用中应通过环境变量设置
DEEPSEEK_API_BASE = os.environ.get("DEEPSEEK_API_BASE", "https://api.deepseek.com")
DEEPSEEK_API_TIMEOUT = 30  # API请求超时时间（秒）
DEEPSEEK_API_MAX_RETRIES = 2  # 最大重试次数

# 初始化DeepSeek客户端
try:
    # 创建带有超时和重试机制的HTTP客户端
    http_client = httpx.Client(
        timeout=DEEPSEEK_API_TIMEOUT,
        transport=httpx.HTTPTransport(retries=DEEPSEEK_API_MAX_RETRIES)
    )
    
    deepseek_client = OpenAI(
        api_key=DEEPSEEK_API_KEY,
        base_url=DEEPSEEK_API_BASE,
        http_client=http_client
    )
    logger.info("DeepSeek API客户端初始化成功，已配置超时和重试机制")
except Exception as e:
    logger.error(f"DeepSeek API客户端初始化失败: {str(e)}")
    logger.exception("详细错误")
    deepseek_client = None

# 创建API路由
router = APIRouter(tags=["music_analysis"])

# 分析请求模型
class AnalysisRequest(BaseModel):
    notes_and_symbols: Dict[str, Any]
    user_id: Optional[int] = None

# 分析结果模型
class AnalysisResponse(BaseModel):
    success: bool
    message: str
    analysis: Optional[Dict[str, Any]] = None

# 使用DeepSeek API分析音乐数据
async def analyze_with_deepseek(data):
    """使用DeepSeek AI进行乐谱分析"""
    if not deepseek_client:
        logger.warning("DeepSeek客户端未初始化，使用规则分析代替")
        return None
        
    try:
        # 构建AI提示
        notes = data.get("notes", [])
        clefs = data.get("clefs", [])
        key_signatures = data.get("key_signatures", ["C"])
        time_signatures = data.get("time_signatures", ["4/4"])
        dynamics = data.get("dynamic_marks", [])
        
        prompt = f"""分析以下乐谱元素并给出专业音乐分析:
音符: {', '.join(notes) if notes else '未检测到'}
谱号: {', '.join(clefs) if clefs else '未检测到'}
调号: {', '.join(key_signatures) if key_signatures else 'C调'}
拍号: {', '.join(time_signatures) if time_signatures else '4/4'}
力度标记: {', '.join(dynamics) if dynamics else '未检测到'}

请提供以下方面的分析:
1. 乐谱类型 (例如：钢琴五线谱、高音谱号五线谱等)
2. 节拍与速度 (基于拍号和音符密度)
3. 调性分析 (基于调号分析调性)
4. 难度评估 (初级、中级、高级)
5. 情感倾向 (例如：明快活泼、忧郁深沉等)

以JSON格式返回，格式如下:
{{
  "score_type": "乐谱类型",
  "tempo_time": "节拍与速度",
  "key_signature": "调性分析",
  "difficulty": "难度评估",
  "mood": "情感倾向"
}}
"""

        # 调用DeepSeek API
        logger.info(f"发送分析请求到DeepSeek API")
        
        # 使用run_in_executor代替to_thread，兼容Python 3.8及以下版本
        loop = asyncio.get_event_loop()
        
        def call_deepseek_api():
            return deepseek_client.chat.completions.create(
                model="deepseek-chat",
                messages=[
                    {"role": "system", "content": "你是一位专业的音乐理论分析专家，擅长分析乐谱元素并给出专业评价。"},
                    {"role": "user", "content": prompt}
                ],
                response_format={"type": "json_object"},
                temperature=0.3
            )
        
        response = await loop.run_in_executor(None, call_deepseek_api)
        
        # 提取JSON结果
        result_text = response.choices[0].message.content
        logger.info(f"收到DeepSeek API响应: {result_text[:100]}...")
        
        try:
            # 尝试解析JSON
            analysis_result = json.loads(result_text)
            return analysis_result
        except json.JSONDecodeError as e:
            logger.error(f"DeepSeek返回的结果不是有效的JSON格式: {e}")
            
            # 尝试提取可能包含在文本中的JSON
            json_pattern = r'\{(?:[^{}]|(?:\{(?:[^{}]|(?:\{[^{}]*\}))*\}))*\}'
            match = re.search(json_pattern, result_text)
            if match:
                try:
                    json_str = match.group(0)
                    logger.info(f"尝试解析提取的JSON: {json_str[:100]}...")
                    extracted_json = json.loads(json_str)
                    return extracted_json
                except json.JSONDecodeError:
                    logger.error("无法解析提取的JSON内容")
            
            # 尝试手动解析结果为JSON格式
            fallback_result = {
                "score_type": "未能识别",
                "tempo_time": "未能识别",
                "key_signature": "未能识别",
                "difficulty": "未能识别",
                "mood": "未能识别"
            }
            
            # 尝试从文本中提取关键信息
            if "乐谱类型" in result_text:
                match = re.search(r'乐谱类型[：:]\s*(.*?)[\n\r]', result_text)
                if match:
                    fallback_result["score_type"] = match.group(1).strip()
            
            if "节拍" in result_text or "速度" in result_text:
                match = re.search(r'节拍与速度[：:]\s*(.*?)[\n\r]', result_text)
                if match:
                    fallback_result["tempo_time"] = match.group(1).strip()
            
            if "调性" in result_text:
                match = re.search(r'调性分析[：:]\s*(.*?)[\n\r]', result_text)
                if match:
                    fallback_result["key_signature"] = match.group(1).strip()
            
            if "难度" in result_text:
                match = re.search(r'难度评估[：:]\s*(.*?)[\n\r]', result_text)
                if match:
                    fallback_result["difficulty"] = match.group(1).strip()
            
            if "情感" in result_text:
                match = re.search(r'情感倾向[：:]\s*(.*?)[\n\r]', result_text)
                if match:
                    fallback_result["mood"] = match.group(1).strip()
            
            logger.info(f"使用回退解析结果: {fallback_result}")
            return fallback_result
            
    except Exception as e:
        logger.error(f"DeepSeek API分析失败: {str(e)}")
        logger.exception("DeepSeek API调用详细错误")
        return None

# 分析音符和符号数据
async def analyze_music_data(data):
    """分析乐谱数据并返回结构化分析结果"""
    try:
        # 尝试使用DeepSeek API分析
        deepseek_result = await analyze_with_deepseek(data)
        if deepseek_result:
            logger.info("使用DeepSeek AI分析成功")
            # 添加分析时间
            deepseek_result["analyzed_at"] = datetime.now().isoformat()
            return deepseek_result
            
        logger.info("DeepSeek分析失败或未启用，使用规则分析")
            
        # 提取关键数据
        notes = data.get("notes", [])
        clefs = data.get("clefs", [])
        key_signatures = data.get("key_signatures", ["C"])
        time_signatures = data.get("time_signatures", ["4/4"])
        dynamics = data.get("dynamic_marks", [])
        
        # 1. 分析乐谱类型
        score_type = determine_score_type(clefs)
        
        # 2. 分析节拍与速度
        tempo_time = determine_tempo_and_time(notes, time_signatures)
        
        # 3. 分析调性
        key_signature = determine_key_signature(key_signatures)
        
        # 4. 分析难度
        difficulty = determine_difficulty(notes, dynamics)
        
        # 5. 分析情感倾向
        mood = determine_mood(key_signatures, dynamics)
        
        # 返回分析结果
        analysis_result = {
            "score_type": score_type,
            "tempo_time": tempo_time,
            "key_signature": key_signature,
            "difficulty": difficulty,
            "mood": mood,
            "analyzed_at": datetime.now().isoformat()
        }
        
        return analysis_result
    
    except Exception as e:
        logger.error(f"分析音乐数据时出错: {str(e)}")
        return None

# 分析乐谱类型
def determine_score_type(clefs):
    """基于谱号确定乐谱类型"""
    if not clefs or len(clefs) == 0:
        return "五线谱"
    
    if "treble" in clefs and "bass" in clefs:
        return "钢琴五线谱"
    elif "treble" in clefs:
        return "高音五线谱"
    elif "bass" in clefs:
        return "低音五线谱"
    else:
        return "五线谱"

# 分析节拍与速度
def determine_tempo_and_time(notes, time_signatures):
    """分析节拍与速度指示"""
    # 获取时间签名
    time_signature = time_signatures[0] if time_signatures else "4/4"
    
    # 简化逻辑：基于音符数量和密度判断速度
    note_count = len(notes)
    
    if note_count > 30:
        tempo = "Allegro (快板)"
    elif note_count > 15:
        tempo = "Moderato (中速)"
    else:
        tempo = "Andante (行板)"
    
    return f"{time_signature}拍，{tempo}"

# 分析调性
def determine_key_signature(key_signatures):
    """分析调性"""
    if not key_signatures or len(key_signatures) == 0:
        return "C大调"
    
    key = key_signatures[0]
    
    # 转换成中文调名
    key_map = {
        "C": "C大调", "Cm": "C小调",
        "G": "G大调", "Gm": "G小调",
        "D": "D大调", "Dm": "D小调",
        "A": "A大调", "Am": "A小调",
        "E": "E大调", "Em": "E小调",
        "B": "B大调", "Bm": "B小调",
        "F#": "F#大调", "F#m": "F#小调",
        "C#": "C#大调", "C#m": "C#小调",
        "F": "F大调", "Fm": "F小调",
        "Bb": "降B大调", "Bbm": "降B小调",
        "Eb": "降E大调", "Ebm": "降E小调",
        "Ab": "降A大调", "Abm": "降A小调",
        "Db": "降D大调", "Dbm": "降D小调",
        "Gb": "降G大调", "Gbm": "降G小调",
        "Cb": "降C大调", "Cbm": "降C小调"
    }
    
    return key_map.get(key, f"{key}调")

# 分析难度
def determine_difficulty(notes, dynamics):
    """分析乐谱难度"""
    # 简化逻辑：基于音符数量和动态变化判断
    note_count = len(notes)
    dynamic_changes = len(dynamics)
    
    # 计算一个难度分数
    difficulty_score = note_count + dynamic_changes * 2
    
    if difficulty_score > 40:
        return "高级"
    elif difficulty_score > 20:
        return "中级"
    else:
        return "初级 - 中级"

# 分析情感倾向
def determine_mood(key_signatures, dynamics):
    """分析情感倾向"""
    # 获取调性
    key = key_signatures[0] if key_signatures else "C"
    is_minor = key.endswith('m') or key.endswith('min')
    
    # 获取主要力度标记
    has_forte = any(d in ['f', 'ff', 'fff'] for d in dynamics)
    has_piano = any(d in ['p', 'pp', 'ppp'] for d in dynamics)
    
    # 基于调性和力度分析情感
    if is_minor:  # 小调
        if has_forte:
            return "激烈悲壮，饱含感情"
        elif has_piano:
            return "忧伤抒情，细腻温柔"
        else:
            return "忧郁沉思，情感内敛"
    else:  # 大调
        if has_forte:
            return "欢快热烈，充满活力"
        elif has_piano:
            return "平静舒缓，明亮温和"
        else:
            return "明快活泼，愉悦积极"

# 路由
@router.post("/analyze")
async def analyze_music(
    analysis_request: AnalysisRequest = Body(...),
    current_user: Optional[int] = Depends(get_current_user)
):
    """分析乐谱数据并返回结构化结果"""
    try:
        # 记录请求信息
        user_id = analysis_request.user_id or current_user
        logger.info(f"收到音乐分析请求: 用户ID={user_id}")
        
        # 执行分析
        analysis_result = await analyze_music_data(analysis_request.notes_and_symbols)
        
        if analysis_result:
            # 返回成功响应
            return AnalysisResponse(
                success=True,
                message="分析成功",
                analysis=analysis_result
            )
        else:
            # 分析失败
            raise HTTPException(
                status_code=422,
                detail="无法分析提供的音乐数据"
            )
    
    except Exception as e:
        logger.error(f"处理分析请求时出错: {str(e)}")
        raise HTTPException(
            status_code=500,
            detail=f"分析处理失败: {str(e)}"
        ) 